////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "WNNetworking/inc/WNWindowsListenConnection.h"
#include "WNNetworking/inc/WNNetworkManager.h"
#include "WNNetworking/inc/WNWindowsINConnection.h"
#include "WNMemory/inc/WNManipulation.h"


WNNetworking::WNWindowsListenConnection::WNWindowsListenConnection(WNNetworkManager& _manager, WNConnectionType _type, WN_UINT16 _port, WNConnectedCallback _connected) :
    WNWindowsConnection(_manager),
    mPort(_port),
    mConnectedCallback(_connected),
    mType(_type),
    mInitialized(false){
    WN_RELEASE_ASSERT_DESC(_type == WNNetworking::eWNReliable, "We do not support unreliable connections yet");
}
    
WNNetworking::WNWindowsListenConnection::~WNWindowsListenConnection() {
}

WNNetworking::WNNetworkingError WNNetworking::WNWindowsListenConnection::Initialize() {
    mSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
    if(INVALID_SOCKET == mSocket) {
        return(eWNCannotCreateSocket);
    }

    sockaddr_in ServerAddress;
    WNMemory::WNMemClrT(&ServerAddress);

    ServerAddress.sin_family = AF_INET;
    ServerAddress.sin_addr.s_addr = INADDR_ANY;
    ServerAddress.sin_port = htons(mPort);

    if(SOCKET_ERROR == bind(mSocket, (struct sockaddr *) &ServerAddress, sizeof(ServerAddress))) {
        closesocket(mSocket);
        return(eWNCannotCreateSocket);
    }

    if(SOCKET_ERROR == listen(mSocket, SOMAXCONN)) {
        closesocket(mSocket);
        return(eWNCannotCreateSocket);
    }

    int nameLen = WN_SNPRINTF(NULL, 0, "Listen:%d", mPort);
    WN_CHAR* name = WNMemory::WNCallocT<WN_CHAR>(nameLen + 1);
    WN_SNPRINTF(name, nameLen+1, "Listen:%d", mPort);
    mConnectionName = name;
    mInitialized = true;
    return(eWNOK);
}

WNNetworking::WNWindowsINConnection* WNNetworking::WNWindowsListenConnection::AcceptConnection() {
    WNNetworking::WNWindowsINConnection* connection = WN_NEW(WNNetworking::WNWindowsINConnection(mManager));
    if(connection->Initialize(mSocket, mConnectedCallback) != eWNOK) {
        WN_DELETE(connection);
    }
    return(connection);
}
